/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#ifndef DEVMON_DEVICE_TOPO_H
#define DEVMON_DEVICE_TOPO_H

#include "device/csr.h"
#include <mc/engine.h>
#include <mutex>
#include <internal/manager.h>
#include <type_traits>
#include "discovery/csr_utils.h"

namespace devmon {

struct topo_node_info {
    std::string name;
    std::string position;
    std::string device_type;
    mc::dict    config_data;

    topo_node_info(std::string n, std::string pos, std::string type, mc::dict config)
        : name(std::move(n)), position(std::move(pos)), device_type(std::move(type)),
          config_data(std::move(config)) {
    }
};
using topo_node_info_ptr = std::shared_ptr<topo_node_info>;

#if defined(BUILD_TYPE) && defined(BUILD_TYPE_DT) && BUILD_TYPE == BUILD_TYPE_DT
// 测试友元类声明 - 只在DT环境生效
class DeviceTopoTestFriend;
#endif



class device_topo {
#if defined(BUILD_TYPE) && defined(BUILD_TYPE_DT) && BUILD_TYPE == BUILD_TYPE_DT
    // 声明测试友元类 - 只在DT环境生效
    friend class DeviceTopoTestFriend;
#endif
    
public:
    static device_topo& get_instance() {
        static device_topo instance;
        return instance;
    }
    ~device_topo() = default;
    void init(mc::engine::service* service);
    bool add_topology(const mc::dict& topology, const mc::dict& objects, const std::string& position);
    void add_device_object(const std::string& position, mc::shared_ptr<mc::engine::abstract_object> device_object);
    void remove_device_object(const std::string& position);
    mc::shared_ptr<mc::engine::abstract_object> get_device_object(const std::string& position);
    void dump_topology(const std::string& directory_path) const;

private:
    device_topo()  = default;
    
    // 成员变量
    std::map<std::string, mc::shared_ptr<mc::engine::abstract_object>> m_device_map;
    std::map<std::string, mc::shared_ptr<mc::engine::abstract_object>> m_chip_map;
    std::map<std::string, mc::shared_ptr<mc::engine::abstract_object>> m_bus_map;
    std::map<std::string, mc::dict>                                     m_connector_config_map;
    mc::engine::service* m_service;
    mutable std::mutex m_topology_mutex;

    // 核心对象管理方法
    mc::shared_ptr<mc::engine::abstract_object> create_topo_object(const topo_node_info_ptr& node_info,
                                                                    mc::shared_ptr<mc::engine::abstract_object> previous_object);

    std::tuple<std::shared_ptr<dev::chip_base>, mc::shared_ptr<mc::engine::abstract_object>> get_chip_node(const topo_node_info_ptr& node_info,
                                                                                mc::shared_ptr<mc::engine::abstract_object> previous_object);

    std::tuple<std::shared_ptr<dev::bus_base>, mc::shared_ptr<mc::engine::abstract_object>> get_bus_node(const topo_node_info_ptr& node_info,
                                                                                 mc::shared_ptr<mc::engine::abstract_object> previous_object);

    // 辅助方法
    mc::engine::abstract_object* get_parent_object(mc::shared_ptr<mc::engine::abstract_object> previous_object);
    mc::shared_ptr<mc::engine::abstract_object> get_or_create_node(const topo_node_info_ptr& node_info,
                                                                    mc::shared_ptr<mc::engine::abstract_object> previous_object,
                                                                    std::map<std::string, mc::shared_ptr<mc::engine::abstract_object>>& node_map);

    // 模板版本的设备对象处理函数
    template<typename T>
    std::shared_ptr<T> find_existing_device_object(const std::string& object_name);
    
    template<typename T>
    std::shared_ptr<T> create_new_device_object(const topo_node_info_ptr& node_info);

    // 使用 make_shared 的辅助方法
    topo_node_info_ptr create_node_info(const std::string& object_name, 
                                        const std::string& position,
                                        const mc::dict& objects);

    // 拓扑处理方法
    using chip_pair = std::pair<std::shared_ptr<dev::chip_base>, mc::shared_ptr<mc::engine::abstract_object>>;
    using bus_pair = std::pair<std::shared_ptr<dev::bus_base>, mc::shared_ptr<mc::engine::abstract_object>>;
    
    void process_buses(const std::string& position, const mc::dict& topology, const mc::dict& objects_data,
                       const chip_pair& parent_chip = {nullptr, nullptr},
                       const mc::variants& buses_override = mc::variants{});
    void process_chips(const std::string& position, const mc::variants& chips, const mc::dict& topology,
                       const mc::dict& objects_data, const bus_pair& parent_bus, const chip_pair& parent_chip);

    // 数据提取方法
    mc::variants get_chips_from_bus(const std::string& bus_name, const mc::dict& topology);
    mc::variants get_buses_from_chip(const std::string& chip_name, const mc::dict& topology);
    mc::variants extract_buses_from_topology(const mc::dict& topology);
    void dump_topology_node(std::string& content, mc::engine::abstract_object* object, int depth,
                            std::set<std::string>& visited,
                            const std::string& prefix, bool is_last) const;
    std::string remove_dev_suffix(const std::string& name) const;
    std::string get_display_name(mc::engine::abstract_object* object) const;

};

} // namespace devmon

#endif // DEVMON_DEVICE_TOPO_H